package com.elves.auth.config;

import com.elves.auth.service.UserService;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.realm.JNDIRealm;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;

import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;

@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfig {

//    @Bean
//    public PasswordEncoder passwordEncoder() {
////        明文密码
////        return NoOpPasswordEncoder.getInstance();
//        return new BCryptPasswordEncoder();
//    }

    @Resource
    UserService userService;

    // 自定义Encoder
    @Bean
    public PasswordEncoder passwordEncoder() {
        // 返回一个不进行任何加密的密码编码器
        return new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                log.info("Encoding password:{}", rawPassword.toString());
                // 直接返回明文密码
                return rawPassword.toString();
            }

            /**
             *
             * @param rawPassword 用户输入密码：the raw password to encode and match
             * @param encodedPassword 系统设定密码：the encoded password from storage to compare with
             * @return
             */
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                log.info("rowPassword:{}|encodePassword:{}", rawPassword, encodedPassword);
                // 比较密码是否一致
                return rawPassword.toString().equals(encodedPassword);
            }
        };
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        log.info("securityFilterChain");
        http.authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests
                .requestMatchers(HttpMethod.POST, "/login").permitAll()
                // 其实没有写路由/login
                .requestMatchers("/login","/login.html","/getPublicKey", "/bootstrap.min.css", "img/login-owl-head.png",
                        "img/login-owl-hand.png", "js/jquery-3.7.1.min.js", "js/jsencrypt.js", "js/crypto-js.min.js").permitAll()
                .anyRequest().authenticated());
        http.formLogin(formLogin -> formLogin
                .loginPage("/login.html")
                //                .defaultSuccessUrl("/home", true)
                //  .defaultSuccessUrl("/index.html", true)
                .defaultSuccessUrl("/")
                .loginProcessingUrl("/login").failureHandler(new CustomAuthenticationFailureHandler())
                .permitAll());
        http.headers(httpSecurityHeadersConfigurer -> {
            httpSecurityHeadersConfigurer.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable);
        });
        // 6.2 版本里这里要使用 csrf.disable() 而不是 withDefault() 方法,withDefault()方法的，个人实践不成功
        // http.csrf(csrf -> csrf.disable());
        http.csrf(AbstractHttpConfigurer::disable);
        return http.build();
    }

    public static class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
                                            AuthenticationException exception) throws IOException, ServletException {
            log.info("request:{}", request);
//            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
//            response.setContentType("application/json;charset=utf-8");
//            PrintWriter writer = response.getWriter();
//            log.info("login exception msg:{}", exception.getMessage());
//            writer.write("{\"error\": \"" + exception.getMessage() + "\"}");
//            writer.flush();

            //   super.setDefaultFailureUrl(securityProperties.getAuthentication().getLoginPage()+"?error");
            // 对错误消息进行URL编码
            String encodedErrorMsg = URLEncoder.encode(exception.getMessage(), "UTF-8");
            super.setDefaultFailureUrl("/login.html?error=" + encodedErrorMsg);
            super.onAuthenticationFailure(request, response, exception);

        }
    }

}